package cn.lbd.income.utils;

import lombok.extern.slf4j.Slf4j;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.engine.export.HtmlExporter;
import net.sf.jasperreports.engine.export.ooxml.JRXlsxExporter;
import net.sf.jasperreports.engine.fill.JRFileVirtualizer;
import net.sf.jasperreports.export.*;
import org.springframework.core.io.ClassPathResource;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * Author: linbd
 * Date: 2020/12/31 09:34
 * Description: Simple for developing JasperReport
 */
@Slf4j
public class JasperReportUtils {
    final static String jasperDir = "report";

    /**
     * 获取jasper文件的相对路径
     *
     * @param fileName 文件名
     * @return
     */
    public static String getJasperFileDir(String fileName) {
        // File.separator就是"\"   =>  report\Blank_A4.jasper
        return jasperDir + File.separator + fileName + ".jasper";
    }

    /**
     * 获取客户需要类型的Mime类型
     *
     * @param type
     * @return
     */
    private static String getContentType(ReportType type) {
        String contentType;
        switch (type) {
            case HTML:
                contentType = "text/html;charset=utf-8";
                break;
            case PDF:
                contentType = "application/pdf";
                break;
            case XLS:
                contentType = "application/vnd.ms-excel";
                break;
            case XLSX:
                contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
                break;
            case XML:
                contentType = "text/xml";
                break;
            case RTF:
                contentType = "application/rtf";
                break;
            case CSV:
                contentType = "text/plain";
                break;
            case DOC:
                contentType = "application/msword";
                break;
            default:
                contentType = "text/html;charset=utf-8";
        }
        return contentType;
    }

    /**
     * 无优化
     * @param jasperStream
     * @param parameters
     * @param list
     * @return
     * @throws JRException
     */
    public static JasperPrint getJasperPrint(InputStream jasperStream, Map parameters, List<?> list) throws JRException {
        JRDataSource dataSource = null;
        //根据list集合，即report是否有要被填充的字段Field
        if (null == list || list.size() == 0) {
            //没有，表示我们不需要传入是个空DataSource
            dataSource = new JREmptyDataSource();
        } else {
            //有，建立一个以collectionList作为数据的数据源。
            //在report中我们就可以使用$F{Field}(是collectionList<Bean> Bean中的属性)来得到List中每个Bean的数据了。
            dataSource = new JRBeanCollectionDataSource(list);
        }
        //核心代码，把Paramters传入JasperReport提供的方法，并返回JasperPrint 对象
        //传入 获取的类路径的Resource的输入流，要填充参数的map(Jasper中Parameters下的值)，根据不同情况的list生成的不同数据源
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, dataSource);
        return jasperPrint;
    }

    static JasperPrint getJasperPrint(InputStream jasperStream, Map parameters, Connection connection) throws JRException {
        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperStream, parameters, connection);
        return jasperPrint;
    }

    /**
     * 大数据量优化JasperPrint
     * @param jasperStream
     * @param parameters
     * @param list
     * @return
     * @throws JRException
     */
    public static JasperPrint getJasperPrintWithPersistence(InputStream jasperStream, Map parameters, List<?> list) throws JRException {
        //解决大数据量保留在内存中,只在内存中保留两页，剩下的放入磁盘中
        JRFileVirtualizer virtualizer = new JRFileVirtualizer(2, "D:/data");
        parameters.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);
        virtualizer.setReadOnly(true);
        System.out.println("д?????");
        JRDataSource dataSource = null;
        //根据list集合，即report是否有要被填充的字段Field
        if (null == list || list.size() == 0) {
            //没有，表示我们不需要传入是个空DataSource
            dataSource = new JREmptyDataSource();
        } else {
            //有，建立一个以collectionList作为数据的数据源。
            //在report中我们就可以使用$F{Field}(是collectionList<Bean> Bean中的属性)来得到List中每个Bean的数据了。
            dataSource = new JRBeanCollectionDataSource(list);
        }
        return JasperFillManager.fillReport(jasperStream, parameters, new JRBeanCollectionDataSource(list));
    }


    /**
     * 导出为Pdf
     *
     * @param jasperPath
     * @param parameters
     * @param list
     * @param response
     * @throws Exception
     */
    public static void exportToPdf(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
        OutputStream outputStream = response.getOutputStream();
        try {
            ClassPathResource resource = new ClassPathResource(jasperPath);
            response.setContentType(getContentType(ReportType.PDF));
            InputStream jasperStream = resource.getInputStream();
            JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);
            JasperExportManager.exportReportToPdfStream(jasperPrint, outputStream);
        } catch (Exception e) {
            log.error("读取报表异常", e);
            outputStream.write("读取报表异常".getBytes());
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }

    /*public static void runToPdf(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
        OutputStream outputStream = response.getOutputStream();
        try {
            ClassPathResource resource = new ClassPathResource(jasperPath);
            response.setContentType(getContentType(ReportType.PDF));
            InputStream jasperStream = resource.getInputStream();
            //JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);
            JasperRunManager.runReportToPdfStream(jasperStream, outputStream, parameters, new JRBeanCollectionDataSource(list));
        } catch (Exception e) {
            log.error("读取报表异常", e);
            outputStream.write("读取报表异常".getBytes());
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }*/

    /**
     * 导出为Xml
     *
     * @param jasperPath
     * @param parameters
     * @param list
     * @param response
     * @throws Exception
     */
    public static void exportToXml(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
        OutputStream outputStream = response.getOutputStream();
        try {
            ClassPathResource resource = new ClassPathResource(jasperPath);
            response.setContentType(getContentType(ReportType.XML));
            InputStream jasperStream = resource.getInputStream();
            JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);
            JasperExportManager.exportReportToXmlStream(jasperPrint, outputStream);
        } catch (Exception e) {
            log.error("读取报表异常", e);
            outputStream.write("读取报表异常".getBytes());
        } finally {
            outputStream.flush();
            outputStream.close();
        }
    }

    /**
     * 导出为Html，常用
     *
     * @param jasperPath
     * @param parameters
     * @param list
     * @param response
     * @throws Exception
     */
    public static void exportToHtml(String jasperPath, Map parameters, List<?> list, HttpServletResponse response) throws Exception {
        response.setHeader("Content-type", "text/html;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType(getContentType(ReportType.HTML));
        PrintWriter out = response.getWriter();
        out.write("<button onclick='jump()'>导出</button> <script>function jump(){ window.location.href='http://localhost:8080/income?type=xlsx'; }</script>");
        HtmlExporter exporter = new HtmlExporter();
        try {
            ClassPathResource resource = new ClassPathResource(jasperPath);
            InputStream jasperStream = resource.getInputStream();
            JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, list);

            exporter.setExporterInput(new SimpleExporterInput(jasperPrint));

            SimpleHtmlReportConfiguration configuration = new SimpleHtmlReportConfiguration();
            exporter.setConfiguration(configuration);

            HtmlExporterOutput outPut = new SimpleHtmlExporterOutput(out);
            exporter.setExporterOutput(outPut);

            exporter.exportReport();
        } catch (Exception e) {
            log.error("读取报表异常", e);
            out.write("读取报表异常");
        } finally {
            out.flush();
            out.close();
        }
    }

    /**
     * 尝试在jasper的模板层面来设计数据源，后端只要传Connection即可
     * @param jasperPath
     * @param parameters
     * @param conn
     * @param response
     * @throws Exception
     */
    public static void exportToHtml(String jasperPath, Map parameters, Connection conn, HttpServletResponse response) throws Exception {
        response.setHeader("Content-type", "text/html;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType(getContentType(ReportType.HTML));
        PrintWriter out = response.getWriter();
        HtmlExporter exporter = new HtmlExporter();
        try {
            ClassPathResource resource = new ClassPathResource(jasperPath);
            InputStream jasperStream = resource.getInputStream();
            JasperPrint jasperPrint = getJasperPrint(jasperStream, parameters, conn);

            exporter.setExporterInput(new SimpleExporterInput(jasperPrint));

            SimpleHtmlReportConfiguration configuration = new SimpleHtmlReportConfiguration();
            exporter.setConfiguration(configuration);

            HtmlExporterOutput outPut = new SimpleHtmlExporterOutput(out);
            exporter.setExporterOutput(outPut);

            exporter.exportReport();
        } catch (Exception e) {
            log.error("读取报表异常", e);
            out.write("读取报表异常");
        } finally {
            out.flush();
            out.close();
        }
    }

    /**
     * 导出为xlsx类型
     * @param jasperPath
     * @param parameter
     * @param list
     * @param response
     * @throws Exception
     */
    public static void exportToExcel(String jasperPath, Map parameter, List<?> list, HttpServletResponse response) throws Exception {
        OutputStream outputStream = null;

        try {
            outputStream = response.getOutputStream();
            ClassPathResource classPathResource = new ClassPathResource(jasperPath);
            response.setContentType(getContentType(ReportType.XLSX));
            String fileName = UUID.randomUUID().toString().toUpperCase() + ".xlsx";
            response.setHeader("Content-Disposition",
                    "attachment;filename=" + new String(fileName.getBytes("utf-8"), "ISO-8859-1"));
            InputStream inputStream = classPathResource.getInputStream();
            JasperPrint jasperPrint = getJasperPrint(inputStream, parameter, list);
            //创建Excel导出类
            JRXlsxExporter exporter = new JRXlsxExporter();
            //设置导出配置项
            SimpleXlsxReportConfiguration conf = new SimpleXlsxReportConfiguration();
            conf.setWhitePageBackground(false);
            conf.setDetectCellType(true);
            exporter.setConfiguration(conf);
            // 设置输入项
            ExporterInput exporterInput = new SimpleExporterInput(jasperPrint);
            exporter.setExporterInput(exporterInput);
            // 设置输出项
            OutputStreamExporterOutput exporterOutput = new SimpleOutputStreamExporterOutput(outputStream);
            exporter.setExporterOutput(exporterOutput);
            //导出报表
            exporter.exportReport();
            // 重定向到资源文件url
            /*response.sendRedirect(completePath);*/
        } catch (Exception e) {
            log.error("读取报表异常", e);
            outputStream.write("读取报表异常".getBytes());

        } finally {
            outputStream.flush();
            outputStream.close();

        }
    }

    /**
     * 日期格式化
     * @return
     */
    public static String convertDate() {
        return new SimpleDateFormat("yyyy-MM-dd").format(new Date());
    }

    /**
     * 导出的枚举类型
     **/
    public enum ReportType {
        HTML,
        PDF,
        XLS,
        XLSX,
        XML,
        RTF,
        CSV,
        DOC
    }
}